package com.lavender.async._async_response;

import com.lavender.async._common.ApiResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * <p>
 * DeferredResult
 * 使用场景：Apollo基于DeferredResult实现长轮询；服务端"推"技术
 * 实现原理：如果没有给DeferredResult setResult，则该请求会hold，直到后台有线程setResult值，那么hold住的请求会响应
 *
 * DeferredResult和WebAsyncTask的区别：
 * DeferredResult：异步响应，会hold住请求。
 * WebAsyncTask：异步响应，不会hold住请求，会直接返回结果。
 *
 * </p>
 *
 * @author: zhu.chen
 * @date: 2021/3/23
 * @version: v1.0.0
 */
@RestController
@RequestMapping("/deferred")
public class DeferredResultResponse {

    private BlockingQueue<DeferredResult<ApiResponse>> queue = new LinkedBlockingQueue<>();

    /**
     * http://localhost:8086/async/deferred/hold
     */
    @GetMapping("hold")
    public DeferredResult<ApiResponse> hold() {
        DeferredResult<ApiResponse> result = new DeferredResult<ApiResponse>();
        queue.add(result);
        return result;
    }

    /**
     * http://localhost:8086/async/deferred/release
     */
    @GetMapping("release")
    public DeferredResult<ApiResponse> release() throws InterruptedException {
        DeferredResult<ApiResponse> result = queue.take();
        result.setResult(ApiResponse.instanceSuccessApiResponse("release"));
        return result;
    }

    //---------------------------------------------------

    /**
     * http://localhost:8086/async/deferred/test1
     * 测试DeferredResult超时完成
     */
    @GetMapping("test1")
    public DeferredResult<ApiResponse> test1() {
        DeferredResult<ApiResponse> result = new DeferredResult<ApiResponse>(5000L);
        result.onTimeout(() -> {
            System.out.println("超时啦!");
        });
        result.onCompletion(() -> {
            System.out.println("异步完成拉！");
        });
        return result;
    }

}
